package learning.pcfg.training;

import java.util.Enumeration;
import java.util.List;

import learning.data.document.TreeDocument;
import learning.pcfg.inference.IParseScorer;
import learning.pcfg.inference.Parse;
import learning.pcfg.inference.Region;
import learning.pcfg.inference.IndexedGrammar.Production;
import learning.pcfg.inference.IndexedGrammar.ProductionType;
import learning.pcfg.model.TerminalScore;
import learning.util.SparseVector;

public class BasicParseScorer implements IParseScorer {

	public static enum Type { ALL_TERMINALS, TRUE_TERMINALS }; 

	private TreeDocument doc;
	private PCFGParameters params;
	private Type type;
	
	BasicParseScorer(Type type) {
		this.type = type;
	}
	
	public float scoreParse(Parse parse) {
        float sum = 0;

        Production prod = params.grammar.productions[parse.production];
        
        if (prod.learnable) {
            // dot product of root node parameter vector and sum of terminal features
            SparseVector parameters = params.productionParameters[parse.production];
            for (int i = parse.region.start; i < parse.region.end; i++)
                sum += parameters.dotProduct(doc.features[i]);
        }

        // add scores of child trees
        if (parse.childParses != null)
            for (Parse cp : parse.childParses)
                sum += cp.score;

        return sum;
	}

	public void scoreTerminals(Region region, List<TerminalScore> scores) {
		if (type == Type.ALL_TERMINALS) {
			
			Enumeration<Production> i = params.grammar.productions(ProductionType.TERMINAL);
			while (i.hasMoreElements()) {
				Production prod = i.nextElement();
                SparseVector parameters = params.productionParameters[prod.id];
                SparseVector features = doc.features[region.start];
                float score = parameters.dotProduct(features);
                scores.add(new TerminalScore(prod.id, prod.lhs, score));
            }
		} else if (type == Type.TRUE_TERMINALS) {
            
			SparseVector features = doc.features[region.start];
            int prodId = params.labelsToTerminals[token.Label];

            SparseVector parameters = params.productionParameters[prodId];
            float score = parameters.dotProduct(features);

            Production prod = params.grammar.productions[prodId];
            scores.add(new TerminalScore(prod.id, prod.lhs, score));		
		}
	}

	public void setDocument(TreeDocument doc) {
		this.doc = doc;
	}

	public void setParameters(PCFGParameters params) {
		this.params = params;
	}
}
